package com.aplikata.evok.ui;

import java.math.BigInteger;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;

import org.primefaces.context.RequestContext;
import org.primefaces.event.DateSelectEvent;
import org.primefaces.event.ScheduleEntrySelectEvent;
import org.primefaces.event.SelectEvent;
import org.primefaces.model.DefaultScheduleEvent;
import org.primefaces.model.LazyScheduleModel;
import org.primefaces.model.ScheduleEvent;
import org.primefaces.model.ScheduleModel;

import com.aplikata.bo.Dept;
import com.aplikata.bo.User;
import com.aplikata.bo.UserEvent;
import com.aplikata.constants.Constants;
import com.aplikata.constants.ConstantsMsg;
import com.aplikata.evok.bo.DoctorSchedule;
import com.aplikata.evok.bo.DomainPatient;
import com.aplikata.evok.bo.Patient;
import com.aplikata.evok.constants.EvokConstants;
import com.aplikata.evok.email.EvokEmailUtil;
import com.aplikata.evok.service.EvokDoctorService;
import com.aplikata.ui.UIBean;
import com.aplikata.util.FacesUtil;
import com.aplikata.util.YunDateUtil;

/**
 * @ClassName: EvokDoctorScheduleQueryBean
 * @Description: TODO
 * @author Huyun
 * @date Oct 22, 2012 2:46:57 PM
 */
@ManagedBean(name = "doctorScheduleQueryBean")
@ViewScoped
public class EvokDoctorScheduleQueryBean extends UIBean {

	private static final long serialVersionUID = 1L;

	@ManagedProperty(value = "#{evokDoctorService}")
	private EvokDoctorService doctorService;
	private ScheduleModel lazyEventModel;
	private ScheduleEvent sEvent = new DefaultScheduleEvent();
	private UserEvent uEvent;
	private DataModel<Object[]> eventModel;
	private Object[] selectedEvents;
	// private LazyDataModel<Object[]> eventLazyModel;

	private String header;
	private DoctorSchedule doctorSchedule;

	private Integer calendarType;
	private String qyPatientName;
	private Long qyDomainPatientId;
	private DataModel<Object[]> therapyModel = new ListDataModel<Object[]>();
	private Object[] therapyObj;

	// for secretary
	private Long deptId;
	private Dept[] departments;
	private User[] doctorList;
	private Long[] selectedDoctorId;
	private Date qyFrom;
	private Date qyTo;
	private Long doctorId;

	@PostConstruct
	public void init() {
		doctorSchedule = new DoctorSchedule(EvokConstants.DOC_RESERVATION_STATUS_NORMAL);
		uEvent = new UserEvent(getSessionUser());
		if (qyFrom == null) {
			qyFrom = YunDateUtil.getDateTime();
		}
	}

	public ScheduleModel getLazyEventModel() {
		if (lazyEventModel == null) {
			lazyEventModel = new LazyScheduleModel() {

				private static final long serialVersionUID = 1L;

				@Override
				public void loadEvents(Date start, Date end) {
					clear();
					if (doctorList == null || doctorList.length == 0)
						return;

					if (selectedDoctorId == null || selectedDoctorId.length == 0) {
						selectedDoctorId = new Long[doctorList.length];
						for (int i = 0; i < doctorList.length; i++) {
							selectedDoctorId[i] = doctorList[i].getId();
						}
					}

					List<ScheduleEvent> list = doctorService.findDoctorAllCalendar(selectedDoctorId, start, end);

					if (list == null || list.isEmpty())
						return;

					for (ScheduleEvent event : list) {
						this.addEvent(event);
					}
				}
			};
		}
		return lazyEventModel;
	}

	// public LazyDataModel<Object[]> getEventLazyModel() {
	// if (eventLazyModel == null) {
	// eventLazyModel = new LazyDataModel<Object[]>() {
	//
	// private static final long serialVersionUID = 1L;
	//
	// @Override
	// public Object getRowKey(Object[] obj) {
	// String key = obj[0].toString() +"|" + ((BigInteger)obj[2]).longValue();
	// return key;
	// }
	//
	// @Override
	// public Object[] getRowData(String rowKey) {
	// String[] keystr = rowKey.split("|");
	// return (Object[]) getRowObject((String)keystr[0],
	// Long.parseLong(keystr[1]));
	// }
	//
	// @Override
	// public void setRowIndex(int rowIndex) {
	// if (rowIndex == -1 || getPageSize() == 0) {
	// super.setRowIndex(-1);
	// } else
	// super.setRowIndex(rowIndex % getPageSize());
	// }
	//
	// @SuppressWarnings("unchecked")
	// @Override
	// public List<Object[]> load(int first, int pageSize, String sortField,
	// SortOrder sortOrder,
	// Map<String, String> filters) {
	// if (qyFrom == null && qyTo == null && (selectedDoctorId == null ||
	// selectedDoctorId.length == 0))
	// return new ArrayList<Object[]>();
	//
	// if (selectedDoctorId == null || selectedDoctorId.length == 0) {
	// selectedDoctorId = new Long[doctorList.length];
	// for (int i = 0; i < doctorList.length; i++) {
	// selectedDoctorId[i] = doctorList[i].getId();
	// }
	// }
	//
	// Object[] obj = doctorService.findDoctorEvents(selectedDoctorId, qyFrom,
	// qyTo, first, pageSize);
	// if(obj == null){
	// return new ArrayList<Object[]>();
	// }
	// eventLazyModel.setRowCount((Integer) obj[0]);
	// return (List<Object[]>) obj[1];
	// }
	// };
	// }
	//
	// return eventLazyModel;
	// }
	//
	// public void setEventLazyModel(LazyDataModel<Object[]> eventLazyModel) {
	// this.eventLazyModel = eventLazyModel;
	// }

	public void queryAction() {
		lazyEventModel = null;
		lazyEventModel = this.getLazyEventModel();
		// eventLazyModel = null;
		// eventLazyModel = this.getEventLazyModel();
	}

	public void resetAction() {
		qyFrom = YunDateUtil.getDateTime();
		qyTo = null;
		selectedDoctorId = null;
		deptId = null;
		doctorList = null;
		doctorList = this.getDoctorList();
		lazyEventModel = null;
		lazyEventModel = this.getLazyEventModel();
	}
	
	public void selectDepartment(){
		doctorList = doctorService.findDomainDoctors(getQyDomainId(), deptId);
	}

	public void onDateSelect(DateSelectEvent selectEvent) {
		sEvent = new DefaultScheduleEvent("", selectEvent.getDate(), selectEvent.getDate());
		calendarType = EvokConstants.CALENDAR_TYPE_PATIENT;
		qyPatientName = null;
		doctorSchedule = new DoctorSchedule(EvokConstants.DOC_RESERVATION_STATUS_NORMAL);
		doctorSchedule.setTimeFrom(selectEvent.getDate());
		doctorSchedule.setTimeTo(selectEvent.getDate());
		qyDomainPatientId = null;
		if (selectedDoctorId != null && selectedDoctorId.length == 1) {
			doctorId = selectedDoctorId[0];
		}
		therapyObj = null;
	}

	public void onEventSelect(ScheduleEntrySelectEvent selectEvent) {
		sEvent = selectEvent.getScheduleEvent();
		Object obj = sEvent.getData();

		if (obj instanceof UserEvent) {
			calendarType = EvokConstants.CALENDAR_TYPE_OTHER;
			uEvent = (UserEvent) obj;
			doctorId = uEvent.getUser().getId();
			doctorSchedule = new DoctorSchedule(EvokConstants.DOC_RESERVATION_STATUS_NORMAL);
		} else if (obj instanceof DoctorSchedule) {
			calendarType = EvokConstants.CALENDAR_TYPE_PATIENT;
			doctorSchedule = (DoctorSchedule) obj;
			if (doctorSchedule.getPatientTherapy() == null) {
				therapyObj = null;
			} else {
				therapyObj = doctorService.getTherapyObjForCalendar(doctorSchedule.getPatientTherapy().getId());
			}

			doctorId = doctorSchedule.getDoctor().getId();
			uEvent = new UserEvent(getSessionUser());
			Patient patient = doctorSchedule.getDomainPatient().getPatient();
			qyDomainPatientId = doctorSchedule.getDomainPatient().getId();
			qyPatientName = patient.getSurname() + " " + patient.getName() + " "
					+ YunDateUtil.formatDate(patient.getBirthday()) + " " + qyDomainPatientId;
		}
	}

	public void editAction() {
		Object[] obj = eventModel.getRowData();
		String ct = (String) obj[0];
		Long bizId = ((BigInteger) obj[2]).longValue();

		if ("private".equals(ct)) {
			calendarType = EvokConstants.CALENDAR_TYPE_OTHER;
			uEvent = (UserEvent) doctorService.get(UserEvent.class, bizId);
			doctorId = uEvent.getUser().getId();
			doctorSchedule = new DoctorSchedule(EvokConstants.DOC_RESERVATION_STATUS_NORMAL);
		} else {
			calendarType = EvokConstants.CALENDAR_TYPE_PATIENT;
			doctorSchedule = (DoctorSchedule) doctorService.get(DoctorSchedule.class, bizId);
			doctorId = doctorSchedule.getDoctor().getId();
			Patient patient = doctorSchedule.getDomainPatient().getPatient();
			qyDomainPatientId = doctorSchedule.getDomainPatient().getId();
			qyPatientName = patient.getSurname() + " " + patient.getName() + " "
					+ YunDateUtil.formatDate(patient.getBirthday()) + " " + qyDomainPatientId;
			if (doctorSchedule.getPatientTherapy() == null) {
				therapyObj = null;
			} else {
				therapyObj = doctorService.getTherapyObjForCalendar(doctorSchedule.getPatientTherapy().getId());
			}
		}
	}

	public void submitEventAction() {
		RequestContext context = RequestContext.getCurrentInstance();
		boolean therapyError = false;

		try {
			User doctor = null;

			if (FacesUtil.isKeyNull(doctorId)) {
				FacesUtil.addErrorMessage(ConstantsMsg.MSG_REQUIRE, FacesUtil.getMessage("evok_doctor_title"));
				therapyError = true;
				context.addCallbackParam("therapyError", therapyError);
				return;
			}
			doctor = (User) doctorService.get(User.class, doctorId);

			doctorService.updateDoctorSchedule(getSessionUser(), doctor, calendarType, uEvent, doctorSchedule,
					qyDomainPatientId, therapyObj);

			// send email
			if (EvokConstants.CALENDAR_TYPE_PATIENT == calendarType.intValue() && doctorSchedule.getStatus() != null
					&& doctorSchedule.getStatus().intValue() == EvokConstants.DOC_RESERVATION_STATUS_CANCEL)
				EvokEmailUtil.sendReservationEmail(doctorSchedule.getDomainPatient().getPatient().getId(),
						doctorSchedule, doctorSchedule.getStatus());

			FacesUtil.addInfoMessage(ConstantsMsg.INFO_SUCCESS, new Object[] { "" });
			lazyEventModel = null;
			lazyEventModel = this.getLazyEventModel();
			// eventLazyModel = null;
			// eventLazyModel = this.getEventLazyModel();
		} catch (Exception e) {
			FacesUtil.addActionListenerException(e, log);
			therapyError = true;
			context.addCallbackParam("therapyError", therapyError);
		}
	}

	public void finishTodayAllAction() {
		// if (selectedSchedules == null) {
		// return;
		// }
		//
		// try {
		// doctorService.updateFinishTodayReservation(selectedSchedules);
		// } catch (Exception e) {
		// FacesUtil.addActionListenerException(e, log);
		// }
	}

	public void deleteEvent() {
		try {
			if (EvokConstants.CALENDAR_TYPE_PATIENT == calendarType.intValue()) {
				doctorService.deleteDoctorSchedule(doctorSchedule, getSessionUser());
				EvokEmailUtil.sendReservationEmail(doctorSchedule.getDomainPatient().getPatient().getId(),
						doctorSchedule, doctorSchedule.getStatus());
				// eventLazyModel = null;
				// eventLazyModel = this.getEventLazyModel();
			}
		} catch (Exception e) {
			FacesUtil.addActionListenerException(e, log);
		}
	}

	public void setLazyEventModel(ScheduleModel lazyEventModel) {
		this.lazyEventModel = lazyEventModel;
	}

	public ScheduleEvent getsEvent() {
		return sEvent;
	}

	public void setsEvent(ScheduleEvent sEvent) {
		this.sEvent = sEvent;
	}

	public UserEvent getuEvent() {
		return uEvent;
	}

	public void setuEvent(UserEvent uEvent) {
		this.uEvent = uEvent;
	}

	public EvokDoctorService getDoctorService() {
		return doctorService;
	}

	public void setDoctorService(EvokDoctorService doctorService) {
		this.doctorService = doctorService;
	}

	public DoctorSchedule getDoctorSchedule() {
		if (FacesUtil.isKeyNull(doctorSchedule.getStatus())) {
			doctorSchedule.setStatus(EvokConstants.DOC_RESERVATION_STATUS_NORMAL);
		}
		return doctorSchedule;
	}

	public void setDoctorSchedule(DoctorSchedule doctorSchedule) {
		this.doctorSchedule = doctorSchedule;
	}

	public String getHeader() {
		header = FacesUtil.getMessage("patient_reservations") + " " + YunDateUtil.formatDateTime("dd/MM/yyyy");
		return header;
	}

	public void setHeader(String header) {
		this.header = header;
	}

	public String getQyPatientName() {
		return qyPatientName;
	}

	public void setQyPatientName(String qyPatientName) {
		this.qyPatientName = qyPatientName;
	}

	@SuppressWarnings("unchecked")
	public List<String> completeQueryName(String query) {
		return (List<String>) doctorService.findByNamedQuery(DomainPatient.QY_FIND_NAME,
				new Object[] { this.getQyDomainId(), query + "%" });
	}

	public void selectPatientName(SelectEvent event) {
		qyPatientName = (String) event.getObject();
		String idString = qyPatientName.substring(qyPatientName.lastIndexOf(" "), qyPatientName.length());
		qyDomainPatientId = Long.parseLong(idString.trim());
	}

	public void openTherapyListAction() {
		if (FacesUtil.isKeyNull(qyDomainPatientId)) {
			therapyModel = new ListDataModel<Object[]>();
			return;
		}

		List<?> qyTherapyList = doctorService.getPatientTherapyListForCanlendar(qyDomainPatientId);
		therapyModel.setWrappedData(qyTherapyList);
	}

	public void chooseTherapyAction() {
		therapyObj = (Object[]) therapyModel.getRowData();
	}

	public void deleteTherapyAction() {
		therapyObj = null;
	}

	public DataModel<Object[]> getTherapyModel() {
		return therapyModel;
	}

	public void setTherapyModel(DataModel<Object[]> therapyModel) {
		this.therapyModel = therapyModel;
	}

	public Object[] getTherapyObj() {
		return therapyObj;
	}

	public void setTherapyObj(Object[] therapyObj) {
		this.therapyObj = therapyObj;
	}

	public Integer getCalendarType() {
		return calendarType;
	}

	public void setCalendarType(Integer calendarType) {
		this.calendarType = calendarType;
	}

	public Object[] getSelectedEvents() {
		return selectedEvents;
	}

	public void setSelectedEvents(Object[] selectedEvents) {
		this.selectedEvents = selectedEvents;
	}

	public User[] getDoctorList() {
		if (doctorList == null) {
			doctorList = doctorService.findDomainDoctors(getQyDomainId(), deptId);
		}
		return doctorList;
	}

	public void setDoctorList(User[] doctorList) {
		this.doctorList = doctorList;
	}

	public Long[] getSelectedDoctorId() {
		return selectedDoctorId;
	}

	public void setSelectedDoctorId(Long[] selectedDoctorId) {
		this.selectedDoctorId = selectedDoctorId;
	}

	public Date getQyFrom() {
		return qyFrom;
	}

	public void setQyFrom(Date qyFrom) {
		this.qyFrom = qyFrom;
	}

	public Date getQyTo() {
		return qyTo;
	}

	public void setQyTo(Date qyTo) {
		this.qyTo = qyTo;
	}

	// @SuppressWarnings("rawtypes")
	// public DataModel<Object[]> getEventModel() {
	// if (eventModel == null) {
	// if (qyFrom == null && qyTo == null && (selectedDoctorId == null ||
	// selectedDoctorId.length == 0))
	// return null;
	//
	// eventModel = new ListDataModel<Object[]>();
	// if (selectedDoctorId == null || selectedDoctorId.length == 0) {
	// selectedDoctorId = new Long[doctorList.length];
	// for (int i = 0; i < doctorList.length; i++) {
	// selectedDoctorId[i] = doctorList[i].getId();
	// }
	// }
	// List eventList = doctorService.findDoctorEvents(selectedDoctorId, qyFrom,
	// qyTo);
	// eventModel.setWrappedData(eventList);
	// }
	// return eventModel;
	// }
	//
	// public void setEventModel(DataModel<Object[]> eventModel) {
	// this.eventModel = eventModel;
	// }

	public Long getQyDomainPatientId() {
		return qyDomainPatientId;
	}

	public void setQyDomainPatientId(Long qyDomainPatientId) {
		this.qyDomainPatientId = qyDomainPatientId;
	}

	public Long getDoctorId() {
		return doctorId;
	}

	public void setDoctorId(Long doctorId) {
		this.doctorId = doctorId;
	}

	@SuppressWarnings("unused")
	private Object getRowObject(String eventType, Long key) {
		if ("private".equals(eventType)) {
			String sqlString = "select 'private', ue.user_id, ue.id, CONCAT(uf.surname, ' ', uf.ime, '<br/>', ue.title) as content, "
					+ " ue.time_from , ue.time_to FROM _user_event ue, _user_reference uf WHERE ue.user_id = uf.user_id ";
			sqlString += " and ue.id = " + key;
			return doctorService.findSingleBySql(sqlString);
		} else {
			String sqlString = "select concat('patient',ds.PRIORITY), uf.user_id, ds.id, CONCAT(uf.surname, ' ', uf.ime, '<br/>', ds.content, '<br/>', p.surname, ' ', p.name) as content,"
					+ " ds.time_from, ds.time_to FROM evk_doctor_schedule ds, _user_reference uf, evk_domain_patient dp, evk_patient p  "
					+ " WHERE ds.doctor_id = uf.user_id and ds.domain_patient_id = dp.id and dp.patient_id=p.id ";
			sqlString += " and ds.id = " + key;
			return doctorService.findSingleBySql(sqlString);
		}
	}

	public Long getDeptId() {
		return deptId;
	}

	public void setDeptId(Long deptId) {
		this.deptId = deptId;
	}

	public Dept[] getDepartments() {                                                 
		if(departments == null){
			departments = doctorService.findByNamedQuery("Dept.findByStatus", new Object[]{
					getSessionDomain().getId(),
					Constants.COMMON_STATUS_NORMAL}).toArray(new Dept[0]);
		}
		return departments;
	}

	public void setDepartments(Dept[] departments) {
		this.departments = departments;
	}

}
